using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Serialization;
using System.Diagnostics;

using WeatherRouter;
using WeatherRouter.Model;
using WeatherRouter.Dispatcher;

namespace WeatherRouterUnitTest
{
    /// <summary>
    /// Quality test suite.
    /// </summary>    
    public class TestSuite
    {
        private static int errorCount;

        public void Run()
        {
            WriteSuiteHeader();
            
            TestConfiguration();
            TestCache();
            TestGetFeed();
            TestDaySpanListSerialization();            
            TestDaySpanListLoadXmlFromFeed();
            TestPreparePacket();
            TestPacketLoadDocument();
            TestTranslitEncode();
            TestFeedInitialValues();
            TestActionInitialValues();
            TestActionParse();
            TestActionToString();

            WriteSuiteFooter();
        }

        #region Helper methods

        private void WriteSuiteHeader()
        {
            Console.WriteLine("Test suite started on " + DateTime.Now.ToString());
            Console.WriteLine();
        }

        private void WriteSuiteFooter()
        {
            Console.WriteLine();
            if (errorCount > 0)
            {
                Console.WriteLine("Test suite Failed with {0} errors", errorCount);
            }
            else
            {
                Console.WriteLine("Test suite Passed");
            }
        }

        private void PrintPassed()
        {
            StackTrace st = new StackTrace();
            StackFrame sf = st.GetFrame(1);

            Console.WriteLine("{0}: Success", sf.GetMethod().Name);
        }

        private void PrintFailed(Exception ex)
        {
            PrintFailed();

            Console.WriteLine();
            Console.WriteLine("Exception in method: ");
            Console.WriteLine(ex.ToString());
            Console.WriteLine();
        }

        private void PrintFailed()
        {
            StackTrace st = new StackTrace();
            StackFrame sf = st.GetFrame(2);

            Console.WriteLine("{0}: Failed", sf.GetMethod().Name);
        }

        #endregion

        private void TestConfiguration()
        {
            StreamWriter persistStorage = null;

            try
            {
                persistStorage = new StreamWriter("configurationTest.xml");
                Configuration configuration = new Configuration();
                Subscriber subscriber = new Subscriber("Bill Gates", "206-1234567", "billg@microsoft.com", true);
                configuration.Subscribers.Add(subscriber);

                Feed feed = new Feed();
                feed.Name = "Rp5.ru";
                feed.Url = "http://rp5.ru/town.php?id=4931&forprint=1";
                feed.Schema = "Rp5.xsl";
                feed.ItemSchema = "Rp5.ru_DaySpan.xsl";
                configuration.Feeds.Add(feed);

                Action action = new Action();
                action.Hour = 1;
                action.LastSent = DateTime.Now.AddDays(-1);
                action.Type = Action.ActionType.Morning;
                action.Feed = feed;
                subscriber.Actions.Add(action);

                XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
                serializer.Serialize(persistStorage, configuration);

                PrintPassed();
            }
            catch (Exception ex)
            {
                PrintFailed(ex);
                errorCount++;
            }
            finally
            {
                if (persistStorage != null)
                {                    
                    persistStorage.Close();
                }
            }
        }

        private void TestCache()
        {
            Cache.Init();

            Feed feed = new Feed();            
            feed.Name = "Rp5.ru";            
            feed.Url = "http://rp5.ru/town.php?id=4931&forprint=1";
            feed.Schema = "Rp5.xsl";

            try
            {
                Cache.Instance.UpdateCache(feed);

                PrintPassed();
            }
            catch (Exception ex)
            {
                PrintFailed(ex);
                errorCount++;
            }
        }

        private void TestGetFeed()
        {
            Cache.Init();

            string feedContent = Cache.Instance.GetFeedContent("Rp5.ru");

            if (feedContent.Length > 0)
            {
                PrintPassed();
            }
            else
            {
                PrintFailed();
            }
        }

        private void TestDaySpanListSerialization()
        {
            try
            {
                Cache.Init();

                string feedContent = Cache.Instance.GetFeedContent("Rp5.ru");

                DaySpan daySpan = new DaySpan();
                daySpan.TimeStamp = DateTime.Now;
                daySpan.Type = DaySpan.DaySpanType.Day;
                daySpan.Item.LoadXml(
                    "<?xml version=\"1.0\" encoding=\"windows-1251\"?>\n" +
                    "<DaySpan timestamp=\"2006-06-06T04:00:00\">\n" +
                    "\t<condition>10%</condition>\n" +
                    "\t<precipitation>0.1</precipitation>\n" +
                    "\t<pressure>744</pressure>\n" +
                    "\t<temperature>+17</temperature>\n" +
                    "\t<humidity>57</humidity>\n" +
                    "\t<wind>4</wind>\n" +
                    "</DaySpan>\n");

                DaySpanList forecast = new DaySpanList();
                forecast.Add(daySpan);

                XmlSerializer serializer = new XmlSerializer(typeof(DaySpanList));
                serializer.Serialize(new StreamWriter("DaySpanListSerTest.xml", false), forecast);

                PrintPassed();

            }
            catch (Exception ex)
            {
                PrintFailed(ex);
                errorCount++;
            }

        }

        private void TestDaySpanListLoadXmlFromFeed()
        {
            try
            {
                Cache.Init();

                string feedContent = Cache.Instance.GetFeedContent("Rp5.ru");
                DaySpanList forecast = new DaySpanList();
                forecast.LoadXmlFromFeedContent(feedContent);

                PrintPassed();
            }
            catch (Exception ex)            
            {
                PrintFailed(ex);
                errorCount++;
            }
        }

        private void TestPreparePacket()
        {
            try
            {
                Engine engine = new Engine();
                engine.Init();
                
                Subscriber subscriber = new Subscriber("Alexander Schmidt", "206-1234567", "aschmidt@lipetsk.ru", true);
                Configuration.Instance.Subscribers.Add(subscriber);
                Configuration.Instance.ConfigPath = Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]);
                Configuration.Instance.Smtp.Address = "smtp.sbcglobal.yahoo.com";

                Feed feed = new Feed();
                feed.Name = "Rp5.ru";
                feed.Url = "http://rp5.ru/town.php?id=4931&forprint=1";
                feed.Schema = "Rp5.xsl";
                Configuration.Instance.Feeds.Add(feed);

                Action action = new Action();
                action.Hour = 1;
                action.LastSent = DateTime.Now.AddDays(-1);
                action.Type = Action.ActionType.Morning;
                action.Feed = feed;
                subscriber.Actions.Add(action);
                
                engine.PreparePacket(subscriber, action);

                PrintPassed();
            }
            catch (Exception ex)
            {
                PrintFailed(ex);
                errorCount++;
            }
        }

        private void TestPacketLoadDocument()
        {
            try
            {
                Feed feed = new Feed();
                feed.Name = "Rp5.ru";
                feed.Url = "http://rp5.ru/town.php?id=4931&forprint=1";
                feed.Schema = "Rp5.xsl";
                feed.ItemSchema = "Rp5.ru_DaySpan.xsl";

                DaySpan daySpan = new DaySpan();
                daySpan.TimeStamp = DateTime.Now;
                daySpan.Type = DaySpan.DaySpanType.Day;
                daySpan.Item.LoadXml(
                    "<?xml version=\"1.0\" encoding=\"windows-1251\"?>\n" +
                    "<DaySpan timestamp=\"2006-06-06T04:00:00\">\n" +
                    "\t<condition>10%</condition>\n" +
                    "\t<precipitation>0.1</precipitation>\n" +
                    "\t<pressure>744</pressure>\n" +
                    "\t<temperature>+17</temperature>\n" +
                    "\t<humidity>57</humidity>\n" +
                    "\t<wind>4</wind>\n" +
                    "</DaySpan>\n");

                Packet packet = new Packet();
                packet.LoadDocument(feed, daySpan, false);

                PrintPassed();
            }
            catch (Exception ex)
            {
                PrintFailed(ex);
                errorCount++;
            }
        }

        private void TestTranslitEncode()
        {
            string input = "<?xml version=\"1.0\" encoding=\"windows-1251\"?>\n" + 
                "<packet>Test message</packet>";
            string output = Translit.Instance.Encode(input);

            if (input == output)
            {
                PrintPassed();
            }
            else
            {
                PrintFailed();
                errorCount++;
            }            
        }

        private void TestFeedInitialValues()
        {   
            Feed feed = new Feed();
            if (feed.SyncHour >= 0)
            {
                PrintPassed();                
            }
            else
            {
                PrintFailed();
                errorCount++;
            }
        }

        private void TestActionInitialValues()
        {
            Action action = new Action();
            PrintPassed();            
        }

        private void TestActionParse()
        {
            Action action = new Action();
            action.Type = Action.Parse("nextmorning");
            if (action.Type != Action.ActionType.NextMorning)
            {
                PrintFailed();
                errorCount++;
            }
            else
            {
                PrintPassed();
            }
        }

        private void TestActionToString()
        {
            Action action = new Action();
            action.Type = Action.ActionType.DayLight;
            string value = action.ToString();
            if (value.ToLower() == "daylight")
            {
                PrintPassed();
            }
            else
            {
                PrintFailed();
            }            
        }
    }
}